package ar.com.pahema.wsaa.dirty;

import java.io.FileInputStream;
import java.io.StringWriter;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.Security;
import java.security.Signature;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Date;
import java.util.GregorianCalendar;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;

import org.apache.cxf.jaxws.JaxWsClientFactoryBean;
import org.bouncycastle.cert.jcajce.JcaCertStore;
import org.bouncycastle.cms.CMSProcessableByteArray;
import org.bouncycastle.cms.CMSSignedData;
import org.bouncycastle.cms.CMSSignedDataGenerator;
import org.bouncycastle.cms.CMSTypedData;
import org.bouncycastle.cms.jcajce.JcaSignerInfoGeneratorBuilder;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.operator.ContentSigner;
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
import org.bouncycastle.operator.jcajce.JcaDigestCalculatorProviderBuilder;
import org.bouncycastle.util.Store;

import sun.misc.BASE64Encoder;
import ar.com.pahema.wsaa.tra.HeaderType;
import ar.com.pahema.wsaa.tra.LoginTicketRequest;
import ar.com.pahema.wsaa.tra.ObjectFactory;

import com.sun.org.apache.xerces.internal.jaxp.datatype.XMLGregorianCalendarImpl;


public class AfipWsaaClient {
	
	public String getRequestTicketResponseWSAA () throws Exception {
		
		String loginTicketResponse = null;
		try {
		  
			JaxWsClientFactoryBean factory = new JaxWsClientFactoryBean();
			
			factory.setServiceClass(LoginCMSService.class);
			factory.setAddress("https://wsaahomo.afip.gov.ar/ws/services/LoginCms");
			
			LoginCMSService loginCMSService = (LoginCMSService)factory.create();
			
			LoginTicketRequest loginTicketRequest = this.createLoginTicketRequest();
			
			byte[] ticketRequestCMSEncoded = this.createCMSMessage(loginTicketRequest);
			
			loginTicketResponse = loginCMSService.loginCms(new String(ticketRequestCMSEncoded));
			
		} catch (Exception e) {
			e.printStackTrace();
		}        
		
		return (loginTicketResponse);
	}
	
	private LoginTicketRequest createLoginTicketRequest(){
		
		ObjectFactory loginTicketRequestFactory = new ObjectFactory();
		LoginTicketRequest loginTicketRequest = loginTicketRequestFactory.createLoginTicketRequest();
		
		Date genTime = new Date();
		GregorianCalendar gentime = new GregorianCalendar();
		GregorianCalendar exptime = new GregorianCalendar();
		Long uniqueId = new Long(genTime.getTime() / 1000);
		
		Long ticketTime = new Long("300000");
		exptime.setTime(new Date(genTime.getTime()+ticketTime));
		
		XMLGregorianCalendarImpl xmlGenTime = new XMLGregorianCalendarImpl(gentime);
		XMLGregorianCalendarImpl xmlExpTime = new XMLGregorianCalendarImpl(exptime);
		
		HeaderType header = loginTicketRequestFactory.createHeaderType();
		header.setSource("cn=marianodenicolo,o=pahema,c=ar,serialNumber=CUIT 2031694739");
		header.setDestination("cn=wsaahomo,o=afip,c=ar,serialNumber=CUIT 33693450239");
		header.setUniqueId(uniqueId);
		header.setGenerationTime(xmlGenTime);
		header.setExpirationTime(xmlExpTime);
		
		loginTicketRequest.setHeader(header);
		loginTicketRequest.setService("wsfe");
		
		return loginTicketRequest;
	}
	
	private String getLoginTicketRequestXML(LoginTicketRequest loginTicketRequest) throws Exception{
		
		JAXBContext context = JAXBContext.newInstance(LoginTicketRequest.class);
		
		Marshaller marshaller = context.createMarshaller();
		marshaller.setProperty(Marshaller.JAXB_ENCODING, "UTF-8");
		marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
		
		
		StringWriter writer = new StringWriter();
		marshaller.marshal(loginTicketRequest, System.out);
		marshaller.marshal(loginTicketRequest, writer);
		
		String ticketRequestString = writer.toString();
		
		return ticketRequestString;
	}
	
	private byte[] createCMSMessage(LoginTicketRequest loginTicketRequest) throws Exception{
		
		PrivateKey pKey = null;
		X509Certificate pCertificate = null;
		byte [] asn1_cms = null;
		String SignerDN = null;
		
		String p12file = "/src/main/webapp/certs/homo/alias_mdn_homo.p12";
		String p12pass = "mariano";
		String signer = "marianodenicolo"; //clavePrivada, mariano, etc

		//
		// Manage Keys & Certificates
		//
		ArrayList<X509Certificate> certList = null;
		try {
			// Create a keystore using keys from the pkcs#12 p12file
			KeyStore ks = KeyStore.getInstance("PKCS12");
			FileInputStream p12stream = new FileInputStream ( p12file ) ;
			ks.load(p12stream, p12pass.toCharArray());
			p12stream.close();

			// Get Certificate & Private key from KeyStore
			pKey = (PrivateKey) ks.getKey(signer, p12pass.toCharArray());
			pCertificate = (X509Certificate)ks.getCertificate(signer);
			SignerDN = pCertificate.getSubjectDN().toString();

			// Create a list of Certificates to include in the final CMS
			certList = new ArrayList<X509Certificate>();
			certList.add(pCertificate);

			if (Security.getProvider("BC") == null) {
				Security.addProvider(new BouncyCastleProvider());
			}

		} 
		catch (Exception e) {
			e.printStackTrace();
		}

		//
		// Create XML Message
		//
		loginTicketRequest.getHeader().setSource(SignerDN);
		
		String loginTicketRequestXML = this.getLoginTicketRequestXML(loginTicketRequest);
		
		Signature signature = Signature.getInstance("SHA1WithRSA", "BC");
        signature.initSign(pKey);
        signature.update(loginTicketRequestXML.getBytes());
		
		
		try {
	        
	        CMSTypedData msg = new CMSProcessableByteArray(signature.sign());
	        Store certs = new JcaCertStore(certList);
	        
	        // Create a new empty CMS Message
	        CMSSignedDataGenerator gen = new CMSSignedDataGenerator();
	        ContentSigner sha1Signer = new JcaContentSignerBuilder("SHA1withRSA").setProvider("BC").build(pKey);
	        // Add a Signer to the Message
	        gen.addSignerInfoGenerator(new JcaSignerInfoGeneratorBuilder(new JcaDigestCalculatorProviderBuilder().setProvider("BC").build()).build(sha1Signer, pCertificate));
	        
	        // Add the Certificate to the Message
	        gen.addCertificates(certs);
	        
	        // Add a Sign of the Data to the Message
	        CMSSignedData sigData = gen.generate(msg, true);

	        BASE64Encoder encoder = new BASE64Encoder();

	        String signedContent = encoder.encode((byte[]) sigData.getSignedContent().getContent());
	        System.out.println("Signed content: " + signedContent + "\n");

	        String envelopedData = encoder.encode(sigData.getEncoded());
	        System.out.println("Enveloped data: " + envelopedData);
			
			
			asn1_cms = envelopedData.getBytes();
		
		} 
		catch (Exception e) {
			e.printStackTrace();
		} 
	
		return (asn1_cms);
		
	}

}
